import tkinter as tk
from tkinter import ttk, messagebox
import csv
import os
import datetime
from decimal import Decimal
import ttkbootstrap as ttkb


class Account:
    def __init__(self, account_id, name, password, balance=0):
        self.account_id = account_id
        self.name = name
        self.password = password
        self.balance = Decimal(str(balance))
        self.records = []

    def save_money(self, amount):
        """存款操作"""
        amount = Decimal(str(amount))
        if amount <= 0:
            return False, "存款金额必须大于0"

        self.balance += amount
        self.records.append({
            "type": "deposit",
            "amount": float(amount),
            "time": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            "balance": float(self.balance)
        })
        return True, f"存款成功，当前余额: {self.balance}"

    def take_money(self, amount):
        """取款操作"""
        amount = Decimal(str(amount))
        if amount <= 0:
            return False, "取款金额必须大于0"
        if amount > self.balance:
            return False, "余额不足"

        self.balance -= amount
        self.records.append({
            "type": "withdraw",
            "amount": float(amount),
            "time": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            "balance": float(self.balance)
        })
        return True, f"取款成功，当前余额: {self.balance}"

    def send_money(self, target_account, amount):
        """转账操作"""
        amount = Decimal(str(amount))
        if amount <= 0:
            return False, "转账金额必须大于0"
        if amount > self.balance:
            return False, "余额不足"

        self.balance -= amount
        target_account.balance += amount

        self.records.append({
            "type": "transfer_out",
            "amount": float(amount),
            "target": target_account.account_id,
            "time": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            "balance": float(self.balance)
        })

        target_account.records.append({
            "type": "transfer_in",
            "amount": float(amount),
            "source": self.account_id,
            "time": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            "balance": float(target_account.balance)
        })

        return True, f"转账成功，当前余额: {self.balance}"

    def get_records(self, count=10):
        """获取最近交易记录"""
        return self.records[-count:] if self.records else []


class Bank:
    def __init__(self, data_file="accounts.csv"):
        self.accounts = {}
        self.data_file = data_file
        self.load_data()

    def load_data(self):
        """从CSV文件加载账户数据"""
        if not os.path.exists(self.data_file):
            return

        try:
            with open(self.data_file, 'r', newline='', encoding='utf-8') as file:
                reader = csv.reader(file)
                next(reader, None)  # 跳过表头

                for row in reader:
                    if len(row) >= 4:  # 确保行数据完整
                        account_id, name, password, balance = row
                        account = Account(account_id, name, password, float(balance))
                        self.accounts[account_id] = account
        except Exception as e:
            messagebox.showerror("错误", f"加载数据出错: {e}")

    def save_data(self):
        """保存账户数据到CSV文件"""
        try:
            with open(self.data_file, 'w', newline='', encoding='utf-8') as file:
                writer = csv.writer(file)
                writer.writerow(["account_id", "name", "password", "balance"])

                for account in self.accounts.values():
                    writer.writerow([
                        account.account_id,
                        account.name,
                        account.password,
                        float(account.balance)
                    ])
        except Exception as e:
            messagebox.showerror("错误", f"保存数据出错: {e}")

    def new_account(self, name, password, initial_money=0):
        """创建新账户"""
        account_id = f"ACC{len(self.accounts) + 1:05d}"
        account = Account(account_id, name, password, initial_money)
        self.accounts[account_id] = account
        self.save_data()
        return account_id

    def find_account(self, account_id):
        """查找账户"""
        return self.accounts.get(account_id)

    def check_password(self, account_id, password):
        """验证账户密码"""
        account = self.find_account(account_id)
        if account and account.password == password:
            return account
        return None


class BankGUI:
    def __init__(self):
        self.bank = Bank()
        self.current_user = None
        
        self.root = ttkb.Window(themename="cosmo")
        self.root.title("银行系统")
        self.root.geometry("800x600")
        
        # 设置样式
        self.style = ttkb.Style("cosmo")
        self.style.configure("TButton", padding=5)
        self.style.configure("TLabel", padding=5)
        self.style.configure("TEntry", padding=5)
        
        self.create_main_frame()
        self.show_login_frame()

    def create_main_frame(self):
        """创建主框架"""
        self.main_frame = ttk.Frame(self.root, padding="10")
        self.main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # 配置网格权重
        self.root.columnconfigure(0, weight=1)
        self.root.rowconfigure(0, weight=1)
        self.main_frame.columnconfigure(0, weight=1)
        self.main_frame.rowconfigure(0, weight=1)

    def clear_frame(self):
        """清除主框架中的所有部件"""
        for widget in self.main_frame.winfo_children():
            widget.destroy()

    def show_login_frame(self):
        """显示登录界面"""
        self.clear_frame()
        
        # 配置主框架的网格权重，使其可以自适应拉伸
        self.main_frame.columnconfigure(0, weight=1)
        self.main_frame.rowconfigure(0, weight=1)
        
        # 创建主登录框架并居中
        main_login_frame = ttk.Frame(self.main_frame)
        main_login_frame.grid(row=0, column=0, sticky="nsew")
        
        # 配置登录框架的网格权重
        main_login_frame.columnconfigure(0, weight=1)
        main_login_frame.rowconfigure(0, weight=1)
        main_login_frame.rowconfigure(1, weight=1)
        main_login_frame.rowconfigure(2, weight=1)
        
        # 创建内容框架
        content_frame = ttk.Frame(main_login_frame)
        content_frame.grid(row=1, column=0)
        
        # 创建输入框架
        input_frame = ttk.Frame(content_frame)
        input_frame.pack(fill="x")
        
        # 账户ID输入框架
        id_frame = ttk.Frame(input_frame)
        id_frame.pack(fill="x", pady=5)
        id_label = ttk.Label(id_frame, text="账户ID:", font=("Arial", 10), width=8, anchor="e")
        id_label.pack(side="left")
        account_id_var = tk.StringVar()
        account_id_entry = ttk.Entry(id_frame, textvariable=account_id_var, width=25)
        account_id_entry.pack(side="left", padx=(5, 0))
        
        # 密码输入框架
        pwd_frame = ttk.Frame(input_frame)
        pwd_frame.pack(fill="x", pady=5)
        pwd_label = ttk.Label(pwd_frame, text="密码:", font=("Arial", 10), width=8, anchor="e")
        pwd_label.pack(side="left")
        password_var = tk.StringVar()
        password_entry = ttk.Entry(pwd_frame, textvariable=password_var, show="*", width=25)
        password_entry.pack(side="left", padx=(5, 0))
        
        # 按钮框架
        button_frame = ttk.Frame(content_frame)
        button_frame.pack(fill="x", pady=(20, 0))
        
        # 设置按钮样式
        self.style.configure("Login.TButton", font=("Arial", 8), padding=2)
        
        # 创建一个居中的按钮容器
        button_container = ttk.Frame(button_frame)
        button_container.pack(anchor="center")
        
        # 添加空白标签来增加距离
        ttk.Label(button_container, text="", width=3).pack(side="left")
        
        # 登录按钮
        login_btn = ttk.Button(button_container, text="登录", 
                             command=lambda: self.login(account_id_var.get(), password_var.get()),
                             style="Login.TButton", width=6)
        login_btn.pack(side="left", padx=15)
        
        # 注册按钮
        register_btn = ttk.Button(button_container, text="注册", 
                                command=self.show_register_frame,
                                style="Login.TButton", width=6)
        register_btn.pack(side="left", padx=3)
        
        # 设置初始焦点
        account_id_entry.focus()

    def show_register_frame(self):
        """显示注册界面"""
        self.clear_frame()
        
        register_frame = ttk.Frame(self.main_frame, padding="20")
        register_frame.grid(row=0, column=0)
        
        # 标题
        ttk.Label(register_frame, text="注册新账户", font=("Arial", 16, "bold")).grid(row=0, column=0, columnspan=2, pady=20)
        
        # 姓名输入
        ttk.Label(register_frame, text="姓名:").grid(row=1, column=0, pady=5)
        name_var = tk.StringVar()
        ttk.Entry(register_frame, textvariable=name_var).grid(row=1, column=1, pady=5)
        
        # 密码输入
        ttk.Label(register_frame, text="密码:").grid(row=2, column=0, pady=5)
        password_var = tk.StringVar()
        ttk.Entry(register_frame, textvariable=password_var, show="*").grid(row=2, column=1, pady=5)
        
        # 初始存款输入
        ttk.Label(register_frame, text="初始存款:").grid(row=3, column=0, pady=5)
        initial_money_var = tk.StringVar()
        ttk.Entry(register_frame, textvariable=initial_money_var).grid(row=3, column=1, pady=5)
        
        # 按钮框架
        button_frame = ttk.Frame(register_frame)
        button_frame.grid(row=4, column=0, columnspan=2, pady=20)
        
        # 注册按钮
        ttk.Button(button_frame, text="注册", 
                  command=lambda: self.register(name_var.get(), password_var.get(), initial_money_var.get())
                  ).grid(row=0, column=0, padx=10)
        
        # 返回按钮
        ttk.Button(button_frame, text="返回", 
                  command=self.show_login_frame
                  ).grid(row=0, column=1, padx=10)

    def show_main_menu(self):
        """显示主菜单"""
        self.clear_frame()
        
        menu_frame = ttk.Frame(self.main_frame, padding="20")
        menu_frame.grid(row=0, column=0)
        
        # 创建欢迎信息框架
        welcome_frame = ttk.Frame(menu_frame)
        welcome_frame.grid(row=0, column=0, pady=20, sticky="ew")
        
        # 确保current_user存在并且有效
        if self.current_user and hasattr(self.current_user, 'name'):
            # 欢迎信息
            ttk.Label(welcome_frame, text=f"欢迎, {self.current_user.name}", 
                     font=("Arial", 16, "bold")).grid(row=0, column=0, pady=(0, 10))
            ttk.Label(welcome_frame, text=f"账户余额: {self.current_user.balance:.1f}", 
                     font=("Arial", 12)).grid(row=1, column=0)
        else:
            messagebox.showerror("错误", "用户信息无效")
            self.logout()
            return
        
        # 创建按钮框架
        button_frame = ttk.Frame(menu_frame)
        button_frame.grid(row=1, column=0, pady=20)
        
        # 功能按钮
        buttons = [
            ("存款", self.show_deposit_frame),
            ("取款", self.show_withdraw_frame),
            ("转账", self.show_transfer_frame),
            ("交易记录", self.show_records_frame),
            ("退出登录", self.logout)
        ]
        
        # 设置按钮样式 - 使用普通的TButton而不是自定义样式
        # self.style.configure("Menu.TButton", font=("Arial", 11), padding=10)
        
        for i, (text, command) in enumerate(buttons):
            btn = ttk.Button(button_frame, text=text, command=command)
            btn.grid(row=i, column=0, pady=5, padx=20, sticky="ew")
            btn.configure(width=20)  # 统一按钮宽度

    def show_deposit_frame(self):
        """显示存款界面"""
        self.clear_frame()
        
        deposit_frame = ttk.Frame(self.main_frame, padding="20")
        deposit_frame.grid(row=0, column=0)
        
        ttk.Label(deposit_frame, text="存款金额:").grid(row=0, column=0, pady=5)
        amount_var = tk.StringVar()
        ttk.Entry(deposit_frame, textvariable=amount_var).grid(row=0, column=1, pady=5)
        
        ttk.Button(deposit_frame, text="确认", 
                  command=lambda: self.deposit(amount_var.get())
                  ).grid(row=1, column=0, pady=20, padx=10)
        
        ttk.Button(deposit_frame, text="返回", 
                  command=self.show_main_menu
                  ).grid(row=1, column=1, pady=20, padx=10)

    def show_withdraw_frame(self):
        """显示取款界面"""
        self.clear_frame()
        
        withdraw_frame = ttk.Frame(self.main_frame, padding="20")
        withdraw_frame.grid(row=0, column=0)
        
        ttk.Label(withdraw_frame, text="取款金额:").grid(row=0, column=0, pady=5)
        amount_var = tk.StringVar()
        ttk.Entry(withdraw_frame, textvariable=amount_var).grid(row=0, column=1, pady=5)
        
        ttk.Button(withdraw_frame, text="确认", 
                  command=lambda: self.withdraw(amount_var.get())
                  ).grid(row=1, column=0, pady=20, padx=10)
        
        ttk.Button(withdraw_frame, text="返回", 
                  command=self.show_main_menu
                  ).grid(row=1, column=1, pady=20, padx=10)

    def show_transfer_frame(self):
        """显示转账界面"""
        self.clear_frame()
        
        transfer_frame = ttk.Frame(self.main_frame, padding="20")
        transfer_frame.grid(row=0, column=0)
        
        ttk.Label(transfer_frame, text="目标账户ID:").grid(row=0, column=0, pady=5)
        target_id_var = tk.StringVar()
        ttk.Entry(transfer_frame, textvariable=target_id_var).grid(row=0, column=1, pady=5)
        
        ttk.Label(transfer_frame, text="转账金额:").grid(row=1, column=0, pady=5)
        amount_var = tk.StringVar()
        ttk.Entry(transfer_frame, textvariable=amount_var).grid(row=1, column=1, pady=5)
        
        ttk.Button(transfer_frame, text="确认", 
                  command=lambda: self.transfer(target_id_var.get(), amount_var.get())
                  ).grid(row=2, column=0, pady=20, padx=10)
        
        ttk.Button(transfer_frame, text="返回", 
                  command=self.show_main_menu
                  ).grid(row=2, column=1, pady=20, padx=10)

    def show_records_frame(self):
        """显示交易记录界面"""
        self.clear_frame()
        
        records_frame = ttk.Frame(self.main_frame, padding="20")
        records_frame.grid(row=0, column=0)
        
        # 创建Treeview
        columns = ("时间", "类型", "金额", "相关账户", "余额")
        tree = ttk.Treeview(records_frame, columns=columns, show="headings")
        
        # 设置列标题
        for col in columns:
            tree.heading(col, text=col)
            tree.column(col, width=100)
        
        # 获取并显示记录
        records = self.current_user.get_records()
        for record in records:
            r_type = record["type"]
            if r_type == "deposit":
                r_type = "存款"
                related = ""
            elif r_type == "withdraw":
                r_type = "取款"
                related = ""
            elif r_type == "transfer_out":
                r_type = "转出"
                related = record["target"]
            elif r_type == "transfer_in":
                r_type = "转入"
                related = record["source"]
                
            tree.insert("", "end", values=(
                record["time"],
                r_type,
                record["amount"],
                related,
                record["balance"]
            ))
        
        tree.grid(row=0, column=0, pady=20)
        
        # 添加滚动条
        scrollbar = ttk.Scrollbar(records_frame, orient="vertical", command=tree.yview)
        scrollbar.grid(row=0, column=1, sticky="ns")
        tree.configure(yscrollcommand=scrollbar.set)
        
        ttk.Button(records_frame, text="返回", 
                  command=self.show_main_menu
                  ).grid(row=1, column=0, columnspan=2, pady=20)

    def login(self, account_id, password):
        """登录处理"""
        if not account_id or not password:
            messagebox.showerror("错误", "请输入账户ID和密码")
            return
            
        # 先查找账户
        account = self.bank.find_account(account_id)
        if not account:
            messagebox.showerror("错误", "账户不存在")
            return
            
        # 验证密码
        if account.password == password:
            self.current_user = account
            self.show_main_menu()
        else:
            messagebox.showerror("错误", "密码错误")

    def register(self, name, password, initial_money):
        """注册处理"""
        if not name or not password:
            messagebox.showerror("错误", "请输入姓名和密码")
            return
            
        try:
            initial_money = float(initial_money) if initial_money else 0
            if initial_money < 0:
                messagebox.showerror("错误", "初始存款不能为负数")
                return
                
            account_id = self.bank.new_account(name, password, initial_money)
            messagebox.showinfo("成功", f"注册成功！您的账户ID是: {account_id}")
            self.show_login_frame()
        except ValueError:
            messagebox.showerror("错误", "请输入有效的金额")

    def deposit(self, amount):
        """存款处理"""
        try:
            amount = float(amount)
            success, message = self.current_user.save_money(amount)
            if success:
                self.bank.save_data()
                messagebox.showinfo("成功", message)
                self.show_main_menu()
            else:
                messagebox.showerror("错误", message)
        except ValueError:
            messagebox.showerror("错误", "请输入有效的金额")

    def withdraw(self, amount):
        """取款处理"""
        try:
            amount = float(amount)
            success, message = self.current_user.take_money(amount)
            if success:
                self.bank.save_data()
                messagebox.showinfo("成功", message)
                self.show_main_menu()
            else:
                messagebox.showerror("错误", message)
        except ValueError:
            messagebox.showerror("错误", "请输入有效的金额")

    def transfer(self, target_id, amount):
        """转账处理"""
        if not target_id:
            messagebox.showerror("错误", "请输入目标账户ID")
            return
            
        target_account = self.bank.find_account(target_id)
        if not target_account:
            messagebox.showerror("错误", "目标账户不存在")
            return
            
        try:
            amount = float(amount)
            success, message = self.current_user.send_money(target_account, amount)
            if success:
                self.bank.save_data()
                messagebox.showinfo("成功", message)
                self.show_main_menu()
            else:
                messagebox.showerror("错误", message)
        except ValueError:
            messagebox.showerror("错误", "请输入有效的金额")

    def logout(self):
        """退出登录"""
        self.current_user = None
        self.show_login_frame()

    def run(self):
        """运行应用程序"""
        self.root.mainloop()


if __name__ == "__main__":
    app = BankGUI()
    app.run() 